/**
  ******************************************************************************
  * @file    stm32f429i_discovery_lcd.c
  * @author  MCD Application Team
  * @version V1.0.1
  * @date    28-October-2013
  * @brief   This file includes the LCD driver for ILI9341 Liquid Crystal
  *          Display Modules of STM32F429I-DISCO kit (MB1075).
  ******************************************************************************
  */

#include "stm32f429i_discovery_lcd.h"
#include "fonts.c"

void delayMs(uint16_t msec);

#define POLY_Y(Z)	((int32_t)((Points + Z)->X))
#define POLY_X(Z)	((int32_t)((Points + Z)->Y))   
#define ABS(X)  	((X) > 0 ? (X) : -(X))

sFONT *LCD_Currentfonts;

/* Global variables to set the written text color */
uint16_t CurrentTextColor = 0x0000;
uint16_t CurrentBackColor = 0xFFFF;

/* Default LCD configuration with LCD Layer 1 */
uint32_t CurrentFrameBuffer = LCD_FRAME_BUFFER;
uint32_t CurrentLayer = LCD_BACKGROUND_LAYER;

void PutPixel(int16_t x, int16_t y);
void LCD_PolyLineRelativeClosed(pPoint Points, uint16_t PointCount, uint16_t Closed);
void LCD_AF_GPIOConfig(void);

/**
  * @brief  DeInitializes the LCD.
  * @param  None
  * @retval None
  */
void LCD_DeInit(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/* LCD Display Off */
	LCD_DisplayOff();

	/* LCD_SPI disable */
	SPI_Cmd(LCD_SPI, DISABLE);

	/* LCD_SPI DeInit */
	SPI_I2S_DeInit(LCD_SPI);

	/* Disable SPI clock  */
	RCC_APB2PeriphClockCmd(LCD_SPI_CLK, DISABLE);

	/* Configure NCS in Output Push-Pull mode */
	GPIO_InitStructure.GPIO_Pin = LCD_NCS_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(LCD_NCS_GPIO_PORT, &GPIO_InitStructure);

	/* Configure SPI pins: SCK, MISO and MOSI */
	GPIO_InitStructure.GPIO_Pin = LCD_SPI_SCK_PIN;
	GPIO_Init(LCD_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = LCD_SPI_MISO_PIN;
	GPIO_Init(LCD_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = LCD_SPI_MOSI_PIN;
	GPIO_Init(LCD_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);

	/* GPIOA configuration */
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_MCO);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6 |
		GPIO_Pin_11 | GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* GPIOB configuration */
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_MCO);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 |
		GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	/* GPIOC configuration */
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_MCO);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	/* GPIOD configuration */
	GPIO_PinAFConfig(GPIOD, GPIO_PinSource3, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_MCO);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	/* GPIOF configuration */
	GPIO_PinAFConfig(GPIOF, GPIO_PinSource10, GPIO_AF_MCO);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOF, &GPIO_InitStructure);

	/* GPIOG configuration */
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource6, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource7, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource10, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource11, GPIO_AF_MCO);
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource12, GPIO_AF_MCO);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_10 |
		GPIO_Pin_11 | GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOG, &GPIO_InitStructure);
}

/**
  * @brief  Initializes the LCD.
  * @param  None
  * @retval None
  */
void LCD_Init(void)
{
	LTDC_InitTypeDef       LTDC_InitStruct;

	/* Configure the LCD Control pins ------------------------------------------*/
	LCD_CtrlLinesConfig();
	LCD_ChipSelect(DISABLE);
	LCD_ChipSelect(ENABLE);

	/* Configure the LCD_SPI interface -----------------------------------------*/
	LCD_SPIConfig();

	/* Power on the LCD --------------------------------------------------------*/
	LCD_PowerOn();

	/* Enable the LTDC Clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_LTDC, ENABLE);

	/* Enable the DMA2D Clock */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2D, ENABLE);

	/* Configure the LCD Control pins */
	LCD_AF_GPIOConfig();

	/* Configure the FMC Parallel interface : SDRAM is used as Frame Buffer for LCD */
	SDRAM_Init();

	/* LTDC Configuration *********************************************************/
	/* Polarity configuration */
	/* Initialize the horizontal synchronization polarity as active low */
	LTDC_InitStruct.LTDC_HSPolarity = LTDC_HSPolarity_AL;
	/* Initialize the vertical synchronization polarity as active low */
	LTDC_InitStruct.LTDC_VSPolarity = LTDC_VSPolarity_AL;
	/* Initialize the data enable polarity as active low */
	LTDC_InitStruct.LTDC_DEPolarity = LTDC_DEPolarity_AL;
	/* Initialize the pixel clock polarity as input pixel clock */
	LTDC_InitStruct.LTDC_PCPolarity = LTDC_PCPolarity_IPC;

	/* Configure R,G,B component values for LCD background color */
	LTDC_InitStruct.LTDC_BackgroundRedValue = 0;
	LTDC_InitStruct.LTDC_BackgroundGreenValue = 0;
	LTDC_InitStruct.LTDC_BackgroundBlueValue = 0;

	/* Configure PLLSAI prescalers for LCD */
	/* Enable Pixel Clock */
	/* PLLSAI_VCO Input = HSE_VALUE / PLL_M = 1 Mhz */
	/* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAI_N = 192 Mhz */
	/* PLLLCDCLK = PLLSAI_VCO Output/PLLSAI_R = 192/4 = 48 Mhz */
	/* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDivR = 48/8 = 6 Mhz */
	RCC_PLLSAIConfig(192, 7, 4);
	RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div8);

	RCC_PLLSAICmd(ENABLE);
	while (RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET) {}	/* Wait for PLLSAI activation */

	/* Timing configuration */
	LTDC_InitStruct.LTDC_HorizontalSync = 9;	/* Configure horizontal synchronization width */
	LTDC_InitStruct.LTDC_VerticalSync = 1;		/* Configure vertical synchronization height */
	LTDC_InitStruct.LTDC_AccumulatedHBP = 29; 	/* Configure accumulated horizontal back porch */
	LTDC_InitStruct.LTDC_AccumulatedVBP = 3;	/* Configure accumulated vertical back porch */
	LTDC_InitStruct.LTDC_AccumulatedActiveW = 269;
	LTDC_InitStruct.LTDC_AccumulatedActiveH = 323;
	LTDC_InitStruct.LTDC_TotalWidth = 279;
	LTDC_InitStruct.LTDC_TotalHeigh = 327;

	LTDC_Init(&LTDC_InitStruct);
}

/**
  * @brief  Initializes the LCD Layers.
  * @param  None
  * @retval None
  */
void LCD_LayerInit(void)
{
	LTDC_Layer_InitTypeDef LTDC_Layer_InitStruct;

	/* Windowing configuration */
	/* In this case all the active display area is used to display a picture then :
		Horizontal start = horizontal synchronization + Horizontal back porch = 30
		Horizontal stop = Horizontal start + window width -1 = 30 + 240 - 1
		Vertical start   = vertical synchronization + vertical back porch = 4
		Vertical stop   = Vertical start + window height -1  = 4 + 320 - 1
		*/
	LTDC_Layer_InitStruct.LTDC_HorizontalStart = 30;
	LTDC_Layer_InitStruct.LTDC_HorizontalStop = (LCD_PIXEL_WIDTH + 30 - 1);
	LTDC_Layer_InitStruct.LTDC_VerticalStart = 4;
	LTDC_Layer_InitStruct.LTDC_VerticalStop = (LCD_PIXEL_HEIGHT + 4 - 1);

	/* Pixel Format configuration*/
	LTDC_Layer_InitStruct.LTDC_PixelFormat = LTDC_Pixelformat_RGB565;

	/* Alpha constant (255 totally opaque) */
	LTDC_Layer_InitStruct.LTDC_ConstantAlpha = 255;

	/* Default Color configuration (configure A,R,G,B component values) */
	LTDC_Layer_InitStruct.LTDC_DefaultColorBlue = 0;
	LTDC_Layer_InitStruct.LTDC_DefaultColorGreen = 0;
	LTDC_Layer_InitStruct.LTDC_DefaultColorRed = 0;
	LTDC_Layer_InitStruct.LTDC_DefaultColorAlpha = 0;

	/* Configure blending factors */
	LTDC_Layer_InitStruct.LTDC_BlendingFactor_1 = LTDC_BlendingFactor1_CA;
	LTDC_Layer_InitStruct.LTDC_BlendingFactor_2 = LTDC_BlendingFactor2_CA;

	/* the length of one line of pixels in bytes + 3 then :
		Line Lenth = Active high width x number of bytes per pixel + 3
		Active high width = LCD_PIXEL_WIDTH
		number of bytes per pixel = 2    (pixel_format : RGB565)
		*/
	LTDC_Layer_InitStruct.LTDC_CFBLineLength = ((LCD_PIXEL_WIDTH * 2) + 3);
	/* the pitch is the increment from the start of one line of pixels to the
		start of the next line in bytes, then :
		Pitch = Active high width x number of bytes per pixel
		*/
	LTDC_Layer_InitStruct.LTDC_CFBPitch = (LCD_PIXEL_WIDTH * 2);

	/* Configure the number of lines */
	LTDC_Layer_InitStruct.LTDC_CFBLineNumber = LCD_PIXEL_HEIGHT;

	/* Start Address configuration : the LCD Frame buffer is defined on SDRAM */
	LTDC_Layer_InitStruct.LTDC_CFBStartAdress = LCD_FRAME_BUFFER;

	/* Initialize LTDC layer 1 */
	LTDC_LayerInit(LTDC_Layer1, &LTDC_Layer_InitStruct);

	/* Configure Layer 2 */
	/* Start Address configuration : the LCD Frame buffer is defined on SDRAM w/ Offset */
	LTDC_Layer_InitStruct.LTDC_CFBStartAdress = LCD_FRAME_BUFFER + BUFFER_OFFSET;

	/* Configure blending factors */
	LTDC_Layer_InitStruct.LTDC_BlendingFactor_1 = LTDC_BlendingFactor1_PAxCA;
	LTDC_Layer_InitStruct.LTDC_BlendingFactor_2 = LTDC_BlendingFactor2_PAxCA;

	LTDC_LayerInit(LTDC_Layer2, &LTDC_Layer_InitStruct);

	LTDC_ReloadConfig(LTDC_IMReload);

	/* Enable foreground & background Layers */
	LTDC_LayerCmd(LTDC_Layer1, ENABLE);
	LTDC_LayerCmd(LTDC_Layer2, ENABLE);

	LTDC_ReloadConfig(LTDC_IMReload);
#ifdef LCD_DEFAULT_FONT
	LCD_SetFont(&LCD_DEFAULT_FONT);
#endif
	LTDC_DitherCmd(ENABLE);
}

/**
  * @brief  Controls LCD Chip Select (CS) pin
  * @param  NewState CS pin state
  * @retval None
  */
void LCD_ChipSelect(FunctionalState NewState)
{
	if (NewState == DISABLE)
	{
		GPIO_ResetBits(LCD_NCS_GPIO_PORT, LCD_NCS_PIN); /* CS pin low: LCD disabled */
	}
	else
	{
		GPIO_SetBits(LCD_NCS_GPIO_PORT, LCD_NCS_PIN); /* CS pin high: LCD enabled */
	}
}

/**
  * @brief  Sets the LCD Layer.
  * @param  Layerx: specifies the Layer foreground or background.
  * @retval None
  */
void LCD_SetLayer(uint32_t Layerx)
{
	if (Layerx == LCD_BACKGROUND_LAYER)
	{
		CurrentFrameBuffer = LCD_FRAME_BUFFER;
		CurrentLayer = LCD_BACKGROUND_LAYER;
	}
	else
	{
		CurrentFrameBuffer = LCD_FRAME_BUFFER + BUFFER_OFFSET;
		CurrentLayer = LCD_FOREGROUND_LAYER;
	}
}

/**
  * @brief  Sets the LCD Text and Background colors.
  * @param  TextColor: specifies the Text Color.
  * @param  BackColor: specifies the Background Color.
  * @retval None
  */
void LCD_SetColors(uint16_t TextColor, uint16_t BackColor)
{
	CurrentTextColor = TextColor;
	CurrentBackColor = BackColor;
}

/**
  * @brief  Gets the LCD Text and Background colors.
  * @param  TextColor: pointer to the variable that will contain the Text
  Color.
  * @param  BackColor: pointer to the variable that will contain the Background
  Color.
  * @retval None
  */
void LCD_GetColors(uint16_t *TextColor, uint16_t *BackColor)
{
	*TextColor = CurrentTextColor;
	*BackColor = CurrentBackColor;
}

/**
  * @brief  Sets the Text color.
  * @param  Color: specifies the Text color code RGB(5-6-5).
  * @retval None
  */
void LCD_SetTextColor(uint16_t Color)
{
	CurrentTextColor = Color;
}

/**
  * @brief  Sets the Background color.
  * @param  Color: specifies the Background color code RGB(5-6-5).
  * @retval None
  */
void LCD_SetBackColor(uint16_t Color)
{
	CurrentBackColor = Color;
}

/**
  * @brief  Sets the Text Font.
  * @param  fonts: specifies the font to be used.
  * @retval None
  */
void LCD_SetFont(sFONT *fonts)
{
	LCD_Currentfonts = fonts;
}

/**
  * @brief  Configure the transparency.
  * @param  transparency: specifies the transparency,
  *         This parameter must range from 0x00 to 0xFF.
  * @retval None
  */
void LCD_SetTransparency(uint8_t transparency)
{
	if (CurrentLayer == LCD_BACKGROUND_LAYER)
	{
		LTDC_LayerAlpha(LTDC_Layer1, transparency);
	}
	else
	{
		LTDC_LayerAlpha(LTDC_Layer2, transparency);
	}
	LTDC_ReloadConfig(LTDC_IMReload);
}

/**
  * @brief  Gets the Text Font.
  * @param  None.
  * @retval the used font.
  */
sFONT *LCD_GetFont(void)
{
	return LCD_Currentfonts;
}

/**
  * @brief  Clears the selected line.
  * @param  Line: the Line to be cleared.
  *   This parameter can be one of the following values:
  *     @arg LCD_LINE_x: where x can be: 0..13 if LCD_Currentfonts is Font16x24
  *                                      0..26 if LCD_Currentfonts is Font12x12 or Font8x12
  *                                      0..39 if LCD_Currentfonts is Font8x8
  * @retval None
  */
void LCD_ClearLine(uint16_t Line)
{
	register uint16_t refcolumn = 0;
	/* Send the string character by character on lCD */
	while ((refcolumn < LCD_PIXEL_WIDTH) && (((refcolumn + LCD_Currentfonts->Width) & 0xFFFF) >= LCD_Currentfonts->Width))
	{
		/* Display one character on LCD */
		LCD_DisplayChar(Line, refcolumn, ' ');
		/* Decrement the column position by 16 */
		refcolumn += LCD_Currentfonts->Width;
	}
}

/**
  * @brief  Clears the hole LCD.
  * @param  Color: the color of the background.
  * @retval None
  */
void LCD_Clear(uint16_t Color)
{
	register uint32_t index;
	register uint32_t dst = CurrentFrameBuffer;

	for (index = 0; index < BUFFER_OFFSET; index++)
	{
		*(__IO uint16_t*)dst = Color;
		dst++;
		dst++;
	}
}

/**
  * @brief  Sets the cursor position.
  * @param  Xpos: specifies the X position.
  * @param  Ypos: specifies the Y position.
  * @retval Display Address
  */
uint32_t LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
	return CurrentFrameBuffer + 2 * (Xpos + (LCD_PIXEL_WIDTH*Ypos));
}

/**
  * @brief  Config and Sets the color Keying.
  * @param  RGBValue: Specifies the Color reference.
  * @retval None
  */
void LCD_SetColorKeying(uint32_t RGBValue)
{
	LTDC_ColorKeying_InitTypeDef   LTDC_colorkeying_InitStruct;

	/* configure the color Keying */
	LTDC_colorkeying_InitStruct.LTDC_ColorKeyBlue = 0x0000FF & RGBValue;
	LTDC_colorkeying_InitStruct.LTDC_ColorKeyGreen = (0x00FF00 & RGBValue) >> 8;
	LTDC_colorkeying_InitStruct.LTDC_ColorKeyRed = (0xFF0000 & RGBValue) >> 16;

	if (CurrentLayer == LCD_BACKGROUND_LAYER)
	{
		/* Enable the color Keying for Layer1 */
		LTDC_ColorKeyingConfig(LTDC_Layer1, &LTDC_colorkeying_InitStruct, ENABLE);
		LTDC_ReloadConfig(LTDC_IMReload);
	}
	else
	{
		/* Enable the color Keying for Layer2 */
		LTDC_ColorKeyingConfig(LTDC_Layer2, &LTDC_colorkeying_InitStruct, ENABLE);
		LTDC_ReloadConfig(LTDC_IMReload);
	}
}

/**
  * @brief  Disable the color Keying.
  * @param  RGBValue: Specifies the Color reference.
  * @retval None
  */
void LCD_ReSetColorKeying(void)
{
	LTDC_ColorKeying_InitTypeDef   LTDC_colorkeying_InitStruct;

	if (CurrentLayer == LCD_BACKGROUND_LAYER)
	{
		/* Disable the color Keying for Layer1 */
		LTDC_ColorKeyingConfig(LTDC_Layer1, &LTDC_colorkeying_InitStruct, DISABLE);
		LTDC_ReloadConfig(LTDC_IMReload);
	}
	else
	{
		/* Disable the color Keying for Layer2 */
		LTDC_ColorKeyingConfig(LTDC_Layer2, &LTDC_colorkeying_InitStruct, DISABLE);
		LTDC_ReloadConfig(LTDC_IMReload);
	}
}

/**
  * @brief  Draws a character on LCD.
  * @param  Xpos: the Line where to display the character shape.
  * @param  Ypos: start column address.
  * @param  c: pointer to the character data.
  * @retval None
  */
#define FONT_STEP_X		8
#define FONT_STEP_Y		16
extern const uint8_t ascii_8x16[];
void LCD_PutChar(uint16_t x, uint16_t y, uint8_t ch, uint16_t fc, uint16_t bc)
{
	uint8_t iy, data, mask;
	uint32_t xpos = (y + (LCD_PIXEL_HEIGHT - 1 - x) * LCD_PIXEL_WIDTH) * 2;
	const uint8_t *code = &ascii_8x16[(ch - ' ') * FONT_STEP_Y];

	for (iy = 0; iy < FONT_STEP_Y; iy++)
	{
		data = *code++;
		mask  = 0x80;
		while (mask != 0)
		{
			if (data & mask)
			{
				*(__IO uint16_t*) (CurrentFrameBuffer + xpos) = fc;
			}
			else
			{
				*(__IO uint16_t*) (CurrentFrameBuffer + xpos) = bc;
			}
			xpos -= (LCD_PIXEL_WIDTH * 2);
			mask >>= 1;
		}
		xpos += (FONT_STEP_X * LCD_PIXEL_WIDTH * 2 + 2);
	}
}

void LCD_SetPoint(uint16_t x, uint16_t y, uint16_t color)
{
	if (x >= LCD_PIXEL_HEIGHT || y >= LCD_PIXEL_WIDTH)
		return;
	*(__IO uint16_t*) (CurrentFrameBuffer + ((uint32_t)(LCD_PIXEL_HEIGHT - 1 - x) * LCD_PIXEL_WIDTH + y) * 2) = color;
}

void LCD_DrawChar(uint16_t Xpos, uint16_t Ypos, const uint16_t *c)
{
	uint32_t index, counter, xpos;
	uint32_t  Xaddress;

	xpos = Xpos * LCD_PIXEL_WIDTH * 2;
	Xaddress = Ypos;

	for (index = 0; index < LCD_Currentfonts->Height; index++)
	{

		for (counter = 0; counter < LCD_Currentfonts->Width; counter++)
		{

			if ((((c[index] & ((0x80 << ((LCD_Currentfonts->Width / 12) * 8)) >> counter)) == 0x00) && (LCD_Currentfonts->Width <= 12)) ||
				(((c[index] & (0x1 << counter)) == 0x00) && (LCD_Currentfonts->Width > 12)))
			{
				/* Write data value to all SDRAM memory */
				*(__IO uint16_t*) (CurrentFrameBuffer + (2 * Xaddress) + xpos) = CurrentBackColor;
			}
			else
			{
				/* Write data value to all SDRAM memory */
				*(__IO uint16_t*) (CurrentFrameBuffer + (2 * Xaddress) + xpos) = CurrentTextColor;
			}
			Xaddress++;
		}
		Xaddress += (LCD_PIXEL_WIDTH - LCD_Currentfonts->Width);
	}
}
/*
void LCD_DrawChar(uint16_t Xpos, uint16_t Ypos, const uint16_t *c)
{
uint32_t iy = 0, ix = 0, xpos =0;
uint32_t Xaddress = 0;
register uint16_t data;
register uint16_t mask;

xpos = Xpos * LCD_PIXEL_WIDTH * 2;
Xaddress += Ypos;

for (iy = 0; iy < LCD_Currentfonts->Height; iy++)
{
data = *c++;
mask = 0x0001;
for (ix = 0; ix < LCD_Currentfonts->Width; ix++)
{
if (data & mask)
//				((((data & ((0x80 << ((LCD_Currentfonts->Width / 12) * 8 )) >> ix)) == 0x00) && (LCD_Currentfonts->Width <= 12))
//			||  (((data & (0x1 << ix)) == 0x00) && (LCD_Currentfonts->Width > 12 ))
//				)
{
*(__IO uint16_t*) (CurrentFrameBuffer + (2 * Xaddress) + xpos) = CurrentTextColor;
}
else
{
*(__IO uint16_t*) (CurrentFrameBuffer + (2 * Xaddress) + xpos) = CurrentBackColor;
}
mask <<= 1;
Xaddress++;
}
Xaddress += (LCD_PIXEL_WIDTH - LCD_Currentfonts->Width);
}
}
*/
/**
  * @brief  Displays one character (16dots width, 24dots height).
  * @param  Line: the Line where to display the character shape .
  *   This parameter can be one of the following values:
  *     @arg Linex: where x can be 0..29
  * @param  Column: start column address.
  * @param  Ascii: character ascii code, must be between 0x20 and 0x7E.
  * @retval None
  */
void LCD_DisplayChar(uint16_t Line, uint16_t Column, uint8_t Ascii)
{
	LCD_DrawChar(Line, Column, &LCD_Currentfonts->table[(Ascii - ' ') * LCD_Currentfonts->Height]);
}

/**
  * @brief  Displays a maximum of 20 char on the LCD.
  * @param  Line: the Line where to display the character shape .
  *   This parameter can be one of the following values:
  *   @arg Linex: where x can be 0..9
  * @param  *ptr: pointer to string to display on LCD.
  * @retval None
  */
void LCD_DisplayStringLine(uint16_t Line, uint8_t *ptr)
{
	uint16_t refcolumn = 0;
	/* Send the string character by character on lCD */
	while (refcolumn < LCD_PIXEL_WIDTH
		&& *ptr != 0
		&& ((refcolumn + LCD_Currentfonts->Width) & 0xFFFF) >= LCD_Currentfonts->Width
		)
	{
		LCD_DisplayChar(Line, refcolumn, *ptr++);
		refcolumn += LCD_Currentfonts->Width;
	}
}

/**
  * @brief  Sets a display window
  * @param  Xpos: specifies the X bottom left position from 0 to 240.
  * @param  Ypos: specifies the Y bottom left position from 0 to 320.
  * @param  Height: display window height, can be a value from 0 to 320.
  * @param  Width: display window width, can be a value from 0 to 240.
  * @retval None
  */
void LCD_SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Height, uint16_t Width)
{

	if (CurrentLayer == LCD_BACKGROUND_LAYER)
	{
		/* reconfigure the layer1 position */
		LTDC_LayerPosition(LTDC_Layer1, Xpos, Ypos);
		LTDC_ReloadConfig(LTDC_IMReload);

		/* reconfigure the layer1 size */
		LTDC_LayerSize(LTDC_Layer1, Width, Height);
		LTDC_ReloadConfig(LTDC_IMReload);
	}
	else
	{
		/* reconfigure the layer2 position */
		LTDC_LayerPosition(LTDC_Layer2, Xpos, Ypos);
		LTDC_ReloadConfig(LTDC_IMReload);

		/* reconfigure the layer2 size */
		LTDC_LayerSize(LTDC_Layer2, Width, Height);
		LTDC_ReloadConfig(LTDC_IMReload);
	}
}

/**
  * @brief  Disables LCD Window mode.
  * @param  None
  * @retval None
  */
void LCD_WindowModeDisable(void)
{
	LCD_SetDisplayWindow(0, 0, LCD_PIXEL_HEIGHT, LCD_PIXEL_WIDTH);
}

/**
  * @brief  Displays a line.
  * @param Xpos: specifies the X position, can be a value from 0 to 240.
  * @param Ypos: specifies the Y position, can be a value from 0 to 320.
  * @param Length: line length.
  * @param Direction: line direction.
  *   This parameter can be one of the following values: LCD_DIR_HORIZONTAL or LCD_DIR_VERTICAL.
  * @retval None
  */
void LCD_DrawLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length, uint8_t Direction)
{
	DMA2D_InitTypeDef      DMA2D_InitStruct;

	volatile uint32_t  Xaddress = 0;
	uint16_t Red_Value = 0, Green_Value = 0, Blue_Value = 0;

	Xaddress = CurrentFrameBuffer + 2 * (LCD_PIXEL_WIDTH*Ypos + Xpos);

	Red_Value = (0xF800 & CurrentTextColor) >> 11;
	Blue_Value = 0x001F & CurrentTextColor;
	Green_Value = (0x07E0 & CurrentTextColor) >> 5;

	/* Configure DMA2D */
	DMA2D_DeInit();
	DMA2D_InitStruct.DMA2D_Mode = DMA2D_R2M;
	DMA2D_InitStruct.DMA2D_CMode = DMA2D_RGB565;
	DMA2D_InitStruct.DMA2D_OutputGreen = Green_Value;
	DMA2D_InitStruct.DMA2D_OutputBlue = Blue_Value;
	DMA2D_InitStruct.DMA2D_OutputRed = Red_Value;
	DMA2D_InitStruct.DMA2D_OutputAlpha = 0x0F;
	DMA2D_InitStruct.DMA2D_OutputMemoryAdd = Xaddress;

	if (Direction == LCD_DIR_HORIZONTAL)
	{
		DMA2D_InitStruct.DMA2D_OutputOffset = 0;
		DMA2D_InitStruct.DMA2D_NumberOfLine = 1;
		DMA2D_InitStruct.DMA2D_PixelPerLine = Length;
	}
	else
	{
		DMA2D_InitStruct.DMA2D_OutputOffset = LCD_PIXEL_WIDTH - 1;
		DMA2D_InitStruct.DMA2D_NumberOfLine = Length;
		DMA2D_InitStruct.DMA2D_PixelPerLine = 1;
	}

	DMA2D_Init(&DMA2D_InitStruct);
	/* Start Transfer */
	DMA2D_StartTransfer();
	/* Wait for CTC Flag activation */
	Xaddress = 50000;
	while (DMA2D_GetFlagStatus(DMA2D_FLAG_TC) == RESET && --Xaddress != 0)
	{ }

}

/**
  * @brief  Displays a rectangle.
  * @param  Xpos: specifies the X position, can be a value from 0 to 240.
  * @param  Ypos: specifies the Y position, can be a value from 0 to 320.
  * @param  Height: display rectangle height, can be a value from 0 to 320.
  * @param  Width: display rectangle width, can be a value from 0 to 240.
  * @retval None
  */
void LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Height, uint16_t Width)
{
	/* draw horizontal lines */
	LCD_DrawLine(Xpos, Ypos, Width, LCD_DIR_HORIZONTAL);
	LCD_DrawLine(Xpos, (Ypos + Height), Width, LCD_DIR_HORIZONTAL);

	/* draw vertical lines */
	LCD_DrawLine(Xpos, Ypos, Height, LCD_DIR_VERTICAL);
	LCD_DrawLine((Xpos + Width), Ypos, Height, LCD_DIR_VERTICAL);
}

/**
  * @brief  Draw a circle.
  * @param  Xpos: specifies the X position, can be a value from 0 to 240.
  * @param  Ypos: specifies the Y position, can be a value from 0 to 320.
  * @param  Radius: radius of the circle.
  * @retval None
  */
void LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius)
{
	int x = -Radius, y = 0, err = 2 - 2 * Radius, e2;
	do {
		*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos - x) + LCD_PIXEL_WIDTH*(Ypos + y)))) = CurrentTextColor;
		*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos + x) + LCD_PIXEL_WIDTH*(Ypos + y)))) = CurrentTextColor;
		*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos + x) + LCD_PIXEL_WIDTH*(Ypos - y)))) = CurrentTextColor;
		*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos - x) + LCD_PIXEL_WIDTH*(Ypos - y)))) = CurrentTextColor;

		e2 = err;
		if (e2 <= y) {
			err += ++y * 2 + 1;
			if (-x == y && e2 <= x) e2 = 0;
		}
		if (e2 > x) err += ++x * 2 + 1;
	} while (x <= 0);
}

/**
  * @brief  Draw a full ellipse.
  * @param  Xpos: specifies the X position, can be a value from 0 to 240.
  * @param  Ypos: specifies the Y position, can be a value from 0 to 320.
  * @param  Radius: minor radius of ellipse.
  * @param  Radius2: major radius of ellipse.
  * @retval None
  */
void LCD_DrawFullEllipse(int Xpos, int Ypos, int Radius, int Radius2)
{
	int x = -Radius, y = 0, err = 2 - 2 * Radius, e2;
	float K = 0, rad1 = 0, rad2 = 0;

	rad1 = Radius;
	rad2 = Radius2;

	if (Radius > Radius2)
	{
		do
		{
			K = (float)(rad1 / rad2);
			LCD_DrawLine((Xpos + x), (Ypos - (uint16_t)(y / K)), (2 * (uint16_t)(y / K) + 1), LCD_DIR_VERTICAL);
			LCD_DrawLine((Xpos - x), (Ypos - (uint16_t)(y / K)), (2 * (uint16_t)(y / K) + 1), LCD_DIR_VERTICAL);

			e2 = err;
			if (e2 <= y)
			{
				err += ++y * 2 + 1;
				if (-x == y && e2 <= x) e2 = 0;
			}
			if (e2 > x) err += ++x * 2 + 1;

		} while (x <= 0);
	}
	else
	{
		y = -Radius2;
		x = 0;
		do
		{
			K = (float)(rad2 / rad1);
			LCD_DrawLine((Xpos - (uint16_t)(x / K)), (Ypos + y), (2 * (uint16_t)(x / K) + 1), LCD_DIR_HORIZONTAL);
			LCD_DrawLine((Xpos - (uint16_t)(x / K)), (Ypos - y), (2 * (uint16_t)(x / K) + 1), LCD_DIR_HORIZONTAL);

			e2 = err;
			if (e2 <= x)
			{
				err += ++x * 2 + 1;
				if (-y == x && e2 <= y) e2 = 0;
			}
			if (e2 > y) err += ++y * 2 + 1;
		} while (y <= 0);
	}
}

/**
  * @brief  Displays an Ellipse.
  * @param  Xpos: specifies the X position, can be a value from 0 to 240.
  * @param  Ypos: specifies the Y position, can be a value from 0 to 320.
  * @param  Radius: specifies Radius.
  * @param  Radius2: specifies Radius2.
  * @retval None
  */
void LCD_DrawEllipse(int Xpos, int Ypos, int Radius, int Radius2)
{
	int x = -Radius, y = 0, err = 2 - 2 * Radius, e2;
	float K = 0, rad1 = 0, rad2 = 0;

	rad1 = Radius;
	rad2 = Radius2;

	if (Radius > Radius2)
	{
		do {
			K = (float)(rad1 / rad2);
			*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos - x) + LCD_PIXEL_WIDTH*(Ypos + (uint16_t)(y / K))))) = CurrentTextColor;
			*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos + x) + LCD_PIXEL_WIDTH*(Ypos + (uint16_t)(y / K))))) = CurrentTextColor;
			*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos + x) + LCD_PIXEL_WIDTH*(Ypos - (uint16_t)(y / K))))) = CurrentTextColor;
			*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos - x) + LCD_PIXEL_WIDTH*(Ypos - (uint16_t)(y / K))))) = CurrentTextColor;

			e2 = err;
			if (e2 <= y) {
				err += ++y * 2 + 1;
				if (-x == y && e2 <= x) e2 = 0;
			}
			if (e2 > x) err += ++x * 2 + 1;
		} while (x <= 0);
	}
	else
	{
		y = -Radius2;
		x = 0;
		do {
			K = (float)(rad2 / rad1);
			*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos - (uint16_t)(x / K)) + LCD_PIXEL_WIDTH*(Ypos + y)))) = CurrentTextColor;
			*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos + (uint16_t)(x / K)) + LCD_PIXEL_WIDTH*(Ypos + y)))) = CurrentTextColor;
			*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos + (uint16_t)(x / K)) + LCD_PIXEL_WIDTH*(Ypos - y)))) = CurrentTextColor;
			*(__IO uint16_t*) (CurrentFrameBuffer + (2 * ((Xpos - (uint16_t)(x / K)) + LCD_PIXEL_WIDTH*(Ypos - y)))) = CurrentTextColor;

			e2 = err;
			if (e2 <= x) {
				err += ++x * 2 + 1;
				if (-y == x && e2 <= y) e2 = 0;
			}
			if (e2 > y) err += ++y * 2 + 1;
		} while (y <= 0);
	}
}

/**
  * @brief  Displays a mono-color picture.
  * @param  Pict: pointer to the picture array.
  * @retval None
  */
void LCD_DrawMonoPict(const uint32_t *Pict)
{
	uint32_t index = 0, counter = 0;


	for (index = 0; index < 2400; index++)
	{
		for (counter = 0; counter < 32; counter++)
		{
			if ((Pict[index] & (1 << counter)) == 0x00)
			{
				*(__IO uint16_t*)(CurrentFrameBuffer) = CurrentBackColor;
			}
			else
			{
				*(__IO uint16_t*)(CurrentFrameBuffer) = CurrentTextColor;
			}
		}
	}
}

/**
  * @brief  Displays a bitmap picture loaded in the internal Flash.
  * @param  BmpAddress: Bmp picture address in the internal Flash.
  * @retval None
  */
void LCD_WriteBMP(uint32_t BmpAddress)
{
	uint32_t index = 0, size = 0, width = 0, height = 0, bit_pixel = 0;
	uint32_t Address;
	uint32_t currentline = 0, linenumber = 0;

	Address = CurrentFrameBuffer;

	/* Read bitmap size */
	size = *(__IO uint16_t *) (BmpAddress + 2);
	size |= (*(__IO uint16_t *) (BmpAddress + 4)) << 16;

	/* Get bitmap data address offset */
	index = *(__IO uint16_t *) (BmpAddress + 10);
	index |= (*(__IO uint16_t *) (BmpAddress + 12)) << 16;

	/* Read bitmap width */
	width = *(uint16_t *)(BmpAddress + 18);
	width |= (*(uint16_t *)(BmpAddress + 20)) << 16;

	/* Read bitmap height */
	height = *(uint16_t *)(BmpAddress + 22);
	height |= (*(uint16_t *)(BmpAddress + 24)) << 16;

	/* Read bit/pixel */
	bit_pixel = *(uint16_t *)(BmpAddress + 28);

	if (CurrentLayer == LCD_BACKGROUND_LAYER)
	{
		/* reconfigure layer size in accordance with the picture */
		LTDC_LayerSize(LTDC_Layer1, width, height);
		LTDC_ReloadConfig(LTDC_VBReload);

		/* Reconfigure the Layer pixel format in accordance with the picture */
		if ((bit_pixel / 8) == 4)
		{
			LTDC_LayerPixelFormat(LTDC_Layer1, LTDC_Pixelformat_ARGB8888);
			LTDC_ReloadConfig(LTDC_VBReload);
		}
		else if ((bit_pixel / 8) == 2)
		{
			LTDC_LayerPixelFormat(LTDC_Layer1, LTDC_Pixelformat_RGB565);
			LTDC_ReloadConfig(LTDC_VBReload);
		}
		else
		{
			LTDC_LayerPixelFormat(LTDC_Layer1, LTDC_Pixelformat_RGB888);
			LTDC_ReloadConfig(LTDC_VBReload);
		}
	}
	else
	{
		/* reconfigure layer size in accordance with the picture */
		LTDC_LayerSize(LTDC_Layer2, width, height);
		LTDC_ReloadConfig(LTDC_VBReload);

		/* Reconfigure the Layer pixel format in accordance with the picture */
		if ((bit_pixel / 8) == 4)
		{
			LTDC_LayerPixelFormat(LTDC_Layer2, LTDC_Pixelformat_ARGB8888);
			LTDC_ReloadConfig(LTDC_VBReload);
		}
		else if ((bit_pixel / 8) == 2)
		{
			LTDC_LayerPixelFormat(LTDC_Layer2, LTDC_Pixelformat_RGB565);
			LTDC_ReloadConfig(LTDC_VBReload);
		}
		else
		{
			LTDC_LayerPixelFormat(LTDC_Layer2, LTDC_Pixelformat_RGB888);
			LTDC_ReloadConfig(LTDC_VBReload);
		}
	}

	/* compute the real size of the picture (without the header)) */
	size = (size - index);

	/* bypass the bitmap header */
	BmpAddress += index;

	/* start copie image from the bottom */
	Address += width*(height - 1)*(bit_pixel / 8);

	for (index = 0; index < size; index++)
	{
		*(__IO uint8_t*) (Address) = *(__IO uint8_t *)BmpAddress;

		/*jump on next byte */
		BmpAddress++;
		Address++;
		currentline++;

		if ((currentline / (bit_pixel / 8)) == width)
		{
			if (linenumber < height)
			{
				linenumber++;
				Address -= (2 * width*(bit_pixel / 8));
				currentline = 0;
			}
		}
	}
}

/**
  * @brief  Displays a full rectangle.
  * @param  Xpos: specifies the X position, can be a value from 0 to 240.
  * @param  Ypos: specifies the Y position, can be a value from 0 to 320.
  * @param  Height: rectangle height.
  * @param  Width: rectangle width.
  * @retval None
  */
void LCD_DrawFullRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
{
	DMA2D_InitTypeDef      DMA2D_InitStruct;

	uint32_t  Xaddress = 0;
	uint16_t Red_Value = 0, Green_Value = 0, Blue_Value = 0;

	Red_Value = (0xF800 & CurrentTextColor) >> 11;
	Blue_Value = 0x001F & CurrentTextColor;
	Green_Value = (0x07E0 & CurrentTextColor) >> 5;

	Xaddress = CurrentFrameBuffer + 2 * (LCD_PIXEL_WIDTH*Ypos + Xpos);

	/* configure DMA2D */
	DMA2D_DeInit();
	DMA2D_InitStruct.DMA2D_Mode = DMA2D_R2M;
	DMA2D_InitStruct.DMA2D_CMode = DMA2D_RGB565;
	DMA2D_InitStruct.DMA2D_OutputGreen = Green_Value;
	DMA2D_InitStruct.DMA2D_OutputBlue = Blue_Value;
	DMA2D_InitStruct.DMA2D_OutputRed = Red_Value;
	DMA2D_InitStruct.DMA2D_OutputAlpha = 0x0F;
	DMA2D_InitStruct.DMA2D_OutputMemoryAdd = Xaddress;
	DMA2D_InitStruct.DMA2D_OutputOffset = (LCD_PIXEL_WIDTH - Width);
	DMA2D_InitStruct.DMA2D_NumberOfLine = Height;
	DMA2D_InitStruct.DMA2D_PixelPerLine = Width;
	DMA2D_Init(&DMA2D_InitStruct);

	/* Start Transfer */
	DMA2D_StartTransfer();

	/* Wait for CTC Flag activation */
	while (DMA2D_GetFlagStatus(DMA2D_FLAG_TC) == RESET)
	{
	}

	LCD_SetTextColor(CurrentTextColor);
}

/**
  * @brief  Displays a full circle.
  * @param  Xpos: specifies the X position, can be a value from 0 to 240.
  * @param  Ypos: specifies the Y position, can be a value from 0 to 320.
  * @param  Radius
  * @retval None
  */
void LCD_DrawFullCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius)
{
	int32_t  D;    /* Decision Variable */
	uint32_t  CurX;/* Current X Value */
	uint32_t  CurY;/* Current Y Value */

	D = 3 - (Radius << 1);

	CurX = 0;
	CurY = Radius;

	while (CurX <= CurY)
	{
		if (CurY > 0)
		{
			LCD_DrawLine(Xpos - CurX, Ypos - CurY, 2 * CurY, LCD_DIR_VERTICAL);
			LCD_DrawLine(Xpos + CurX, Ypos - CurY, 2 * CurY, LCD_DIR_VERTICAL);
		}

		if (CurX > 0)
		{
			LCD_DrawLine(Xpos - CurY, Ypos - CurX, 2 * CurX, LCD_DIR_VERTICAL);
			LCD_DrawLine(Xpos + CurY, Ypos - CurX, 2 * CurX, LCD_DIR_VERTICAL);
		}
		if (D < 0)
		{
			D += (CurX << 2) + 6;
		}
		else
		{
			D += ((CurX - CurY) << 2) + 10;
			CurY--;
		}
		CurX++;
	}

	LCD_DrawCircle(Xpos, Ypos, Radius);
}

/**
  * @brief  Displays an uni-line (between two points).
  * @param  x1: specifies the point 1 x position.
  * @param  y1: specifies the point 1 y position.
  * @param  x2: specifies the point 2 x position.
  * @param  y2: specifies the point 2 y position.
  * @retval None
  */
void LCD_DrawUniLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
	int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
		yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0,
		curpixel = 0;

	deltax = ABS(x2 - x1);        /* The difference between the x's */
	deltay = ABS(y2 - y1);        /* The difference between the y's */
	x = x1;                       /* Start x off at the first pixel */
	y = y1;                       /* Start y off at the first pixel */

	if (x2 >= x1)                 /* The x-values are increasing */
	{
		xinc1 = 1;
		xinc2 = 1;
	}
	else                          /* The x-values are decreasing */
	{
		xinc1 = -1;
		xinc2 = -1;
	}

	if (y2 >= y1)                 /* The y-values are increasing */
	{
		yinc1 = 1;
		yinc2 = 1;
	}
	else                          /* The y-values are decreasing */
	{
		yinc1 = -1;
		yinc2 = -1;
	}

	if (deltax >= deltay)         /* There is at least one x-value for every y-value */
	{
		xinc1 = 0;                  /* Don't change the x when numerator >= denominator */
		yinc2 = 0;                  /* Don't change the y for every iteration */
		den = deltax;
		num = deltax / 2;
		numadd = deltay;
		numpixels = deltax;         /* There are more x-values than y-values */
	}
	else                          /* There is at least one y-value for every x-value */
	{
		xinc2 = 0;                  /* Don't change the x for every iteration */
		yinc1 = 0;                  /* Don't change the y when numerator >= denominator */
		den = deltay;
		num = deltay / 2;
		numadd = deltax;
		numpixels = deltay;         /* There are more y-values than x-values */
	}

	for (curpixel = 0; curpixel <= numpixels; curpixel++)
	{
		PutPixel(x, y);             /* Draw the current pixel */
		num += numadd;              /* Increase the numerator by the top of the fraction */
		if (num >= den)             /* Check if numerator >= denominator */
		{
			num -= den;               /* Calculate the new numerator value */
			x += xinc1;               /* Change the x as appropriate */
			y += yinc1;               /* Change the y as appropriate */
		}
		x += xinc2;                 /* Change the x as appropriate */
		y += yinc2;                 /* Change the y as appropriate */
	}
}

/**
  * @brief  Displays an triangle.
  * @param  Points: pointer to the points array.
  * @retval None
  */
void LCD_Triangle(pPoint Points, uint16_t PointCount)
{
	int16_t X = 0, Y = 0;
	pPoint First = Points;

	if (PointCount != 3)
	{
		return;
	}

	while (--PointCount)
	{
		X = Points->X;
		Y = Points->Y;
		Points++;
		LCD_DrawUniLine(X, Y, Points->X, Points->Y);
	}
	LCD_DrawUniLine(First->X, First->Y, Points->X, Points->Y);
}

/**
  * @brief  Fill an triangle (between 3 points).
  * @param  x1..3: x position of triangle point 1..3.
  * @param  y1..3: y position of triangle point 1..3.
  * @retval None
  */
void LCD_FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3)
{

	int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
		yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0,
		curpixel = 0;

	deltax = ABS(x2 - x1);        /* The difference between the x's */
	deltay = ABS(y2 - y1);        /* The difference between the y's */
	x = x1;                       /* Start x off at the first pixel */
	y = y1;                       /* Start y off at the first pixel */

	if (x2 >= x1)                 /* The x-values are increasing */
	{
		xinc1 = 1;
		xinc2 = 1;
	}
	else                          /* The x-values are decreasing */
	{
		xinc1 = -1;
		xinc2 = -1;
	}

	if (y2 >= y1)                 /* The y-values are increasing */
	{
		yinc1 = 1;
		yinc2 = 1;
	}
	else                          /* The y-values are decreasing */
	{
		yinc1 = -1;
		yinc2 = -1;
	}

	if (deltax >= deltay)         /* There is at least one x-value for every y-value */
	{
		xinc1 = 0;                  /* Don't change the x when numerator >= denominator */
		yinc2 = 0;                  /* Don't change the y for every iteration */
		den = deltax;
		num = deltax / 2;
		numadd = deltay;
		numpixels = deltax;         /* There are more x-values than y-values */
	}
	else                          /* There is at least one y-value for every x-value */
	{
		xinc2 = 0;                  /* Don't change the x for every iteration */
		yinc1 = 0;                  /* Don't change the y when numerator >= denominator */
		den = deltay;
		num = deltay / 2;
		numadd = deltax;
		numpixels = deltay;         /* There are more y-values than x-values */
	}

	for (curpixel = 0; curpixel <= numpixels; curpixel++)
	{
		LCD_DrawUniLine(x, y, x3, y3);

		num += numadd;              /* Increase the numerator by the top of the fraction */
		if (num >= den)             /* Check if numerator >= denominator */
		{
			num -= den;               /* Calculate the new numerator value */
			x += xinc1;               /* Change the x as appropriate */
			y += yinc1;               /* Change the y as appropriate */
		}
		x += xinc2;                 /* Change the x as appropriate */
		y += yinc2;                 /* Change the y as appropriate */
	}


}
/**
  * @brief  Displays an poly-line (between many points).
  * @param  Points: pointer to the points array.
  * @param  PointCount: Number of points.
  * @retval None
  */
void LCD_PolyLine(pPoint Points, uint16_t PointCount)
{
	int16_t X = 0, Y = 0;

	if (PointCount < 2)
	{
		return;
	}

	while (--PointCount)
	{
		X = Points->X;
		Y = Points->Y;
		Points++;
		LCD_DrawUniLine(X, Y, Points->X, Points->Y);
	}
}

/**
  * @brief  Displays an relative poly-line (between many points).
  * @param  Points: pointer to the points array.
  * @param  PointCount: Number of points.
  * @param  Closed: specifies if the draw is closed or not.
  *           1: closed, 0 : not closed.
  * @retval None
  */
void LCD_PolyLineRelativeClosed(pPoint Points, uint16_t PointCount, uint16_t Closed)
{
	int16_t X = 0, Y = 0;
	pPoint First = Points;

	if (PointCount < 2)
	{
		return;
	}
	X = Points->X;
	Y = Points->Y;
	while (--PointCount)
	{
		Points++;
		LCD_DrawUniLine(X, Y, X + Points->X, Y + Points->Y);
		X = X + Points->X;
		Y = Y + Points->Y;
	}
	if (Closed)
	{
		LCD_DrawUniLine(First->X, First->Y, X, Y);
	}
}

/**
  * @brief  Displays a closed poly-line (between many points).
  * @param  Points: pointer to the points array.
  * @param  PointCount: Number of points.
  * @retval None
  */
void LCD_ClosedPolyLine(pPoint Points, uint16_t PointCount)
{
	LCD_PolyLine(Points, PointCount);
	LCD_DrawUniLine(Points->X, Points->Y, (Points + PointCount - 1)->X, (Points + PointCount - 1)->Y);
}

/**
  * @brief  Displays a relative poly-line (between many points).
  * @param  Points: pointer to the points array.
  * @param  PointCount: Number of points.
  * @retval None
  */
void LCD_PolyLineRelative(pPoint Points, uint16_t PointCount)
{
	LCD_PolyLineRelativeClosed(Points, PointCount, 0);
}

/**
  * @brief  Displays a closed relative poly-line (between many points).
  * @param  Points: pointer to the points array.
  * @param  PointCount: Number of points.
  * @retval None
  */
void LCD_ClosedPolyLineRelative(pPoint Points, uint16_t PointCount)
{
	LCD_PolyLineRelativeClosed(Points, PointCount, 1);
}

/**
  * @brief  Displays a  full poly-line (between many points).
  * @param  Points: pointer to the points array.
  * @param  PointCount: Number of points.
  * @retval None
  */
void LCD_FillPolyLine(pPoint Points, uint16_t PointCount)
{

	int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0;
	uint16_t  IMAGE_LEFT = 0, IMAGE_RIGHT = 0, IMAGE_TOP = 0, IMAGE_BOTTOM = 0;

	IMAGE_LEFT = IMAGE_RIGHT = Points->X;
	IMAGE_TOP = IMAGE_BOTTOM = Points->Y;

	for (counter = 1; counter < PointCount; counter++)
	{
		pixelX = POLY_X(counter);
		if (pixelX < IMAGE_LEFT)
		{
			IMAGE_LEFT = pixelX;
		}
		if (pixelX > IMAGE_RIGHT)
		{
			IMAGE_RIGHT = pixelX;
		}

		pixelY = POLY_Y(counter);
		if (pixelY < IMAGE_TOP)
		{
			IMAGE_TOP = pixelY;
		}
		if (pixelY > IMAGE_BOTTOM)
		{
			IMAGE_BOTTOM = pixelY;
		}
	}

	if (PointCount < 2)
	{
		return;
	}

	X_center = (IMAGE_LEFT + IMAGE_RIGHT) / 2;
	Y_center = (IMAGE_BOTTOM + IMAGE_TOP) / 2;

	X_first = Points->X;
	Y_first = Points->Y;

	while (--PointCount)
	{
		X = Points->X;
		Y = Points->Y;
		Points++;
		X2 = Points->X;
		Y2 = Points->Y;

		LCD_FillTriangle(X, X2, X_center, Y, Y2, Y_center);
		LCD_FillTriangle(X, X_center, X2, Y, Y_center, Y2);
		LCD_FillTriangle(X_center, X2, X, Y_center, Y2, Y);
	}

	LCD_FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center);
	LCD_FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2);
	LCD_FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first);
}

/**
  * @brief  Writes command to select the LCD register.
  * @param  LCD_Reg: address of the selected register.
  * @retval None
  */
void LCD_WriteCommand(uint8_t LCD_Reg)
{
	/* Reset WRX to send command */
	LCD_CtrlLinesWrite(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, Bit_RESET);

	/* Reset LCD control line(/CS) and Send command */
	LCD_ChipSelect(DISABLE);
	SPI_I2S_SendData(LCD_SPI, LCD_Reg);

	/* Wait until a data is sent(not busy), before config /CS HIGH */

	while (SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_TXE) == RESET);

	while (SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_BSY) != RESET);

	LCD_ChipSelect(ENABLE);
}

/**
  * @brief  Writes data to select the LCD register.
  *         This function must be used after LCD_WriteCommand() function
  * @param  value: data to write to the selected register.
  * @retval None
  */
void LCD_WriteData(uint8_t value)
{
	/* Set WRX to send data */
	LCD_CtrlLinesWrite(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, Bit_SET);

	/* Reset LCD control line(/CS) and Send data */
	LCD_ChipSelect(DISABLE);
	SPI_I2S_SendData(LCD_SPI, value);

	/* Wait until a data is sent(not busy), before config /CS HIGH */

	while (SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_TXE) == RESET);

	while (SPI_I2S_GetFlagStatus(LCD_SPI, SPI_I2S_FLAG_BSY) != RESET);

	LCD_ChipSelect(ENABLE);
}

/**
  * @brief  Configure the LCD controller (Power On sequence as described in ILI9341 Datasheet)
  * @param  None
  * @retval None
  */
void LCD_PowerOn(void)
{
	LCD_WriteCommand(0xCA);
	LCD_WriteData(0xC3);
	LCD_WriteData(0x08);
	LCD_WriteData(0x50);
	LCD_WriteCommand(LCD_POWERB);
	LCD_WriteData(0x00);
	LCD_WriteData(0xC1);
	LCD_WriteData(0x30);
	LCD_WriteCommand(LCD_POWER_SEQ);
	LCD_WriteData(0x64);
	LCD_WriteData(0x03);
	LCD_WriteData(0x12);
	LCD_WriteData(0x81);
	LCD_WriteCommand(LCD_DTCA);
	LCD_WriteData(0x85);
	LCD_WriteData(0x00);
	LCD_WriteData(0x78);
	LCD_WriteCommand(LCD_POWERA);
	LCD_WriteData(0x39);
	LCD_WriteData(0x2C);
	LCD_WriteData(0x00);
	LCD_WriteData(0x34);
	LCD_WriteData(0x02);
	LCD_WriteCommand(LCD_PRC);
	LCD_WriteData(0x20);
	LCD_WriteCommand(LCD_DTCB);
	LCD_WriteData(0x00);
	LCD_WriteData(0x00);
	LCD_WriteCommand(LCD_FRC);
	LCD_WriteData(0x00);
	LCD_WriteData(0x1B);
	LCD_WriteCommand(LCD_DFC);
	LCD_WriteData(0x0A);
	LCD_WriteData(0xA2);
	LCD_WriteCommand(LCD_POWER1);
	LCD_WriteData(0x10);
	LCD_WriteCommand(LCD_POWER2);
	LCD_WriteData(0x10);
	LCD_WriteCommand(LCD_VCOM1);
	LCD_WriteData(0x45);
	LCD_WriteData(0x15);
	LCD_WriteCommand(LCD_VCOM2);
	LCD_WriteData(0x90);
	LCD_WriteCommand(LCD_MAC);
	LCD_WriteData(0xC8);
	LCD_WriteCommand(LCD_3GAMMA_EN);
	LCD_WriteData(0x00);
	LCD_WriteCommand(LCD_RGB_INTERFACE);
	LCD_WriteData(0xC2);
	LCD_WriteCommand(LCD_DFC);
	LCD_WriteData(0x0A);
	LCD_WriteData(0xA7);
	LCD_WriteData(0x27);
	LCD_WriteData(0x04);

	/* colomn address set */
	LCD_WriteCommand(LCD_COLUMN_ADDR);
	LCD_WriteData(0x00);
	LCD_WriteData(0x00);
	LCD_WriteData(0x00);
	LCD_WriteData(0xEF);
	/* Page Address Set */
	LCD_WriteCommand(LCD_PAGE_ADDR);
	LCD_WriteData(0x00);
	LCD_WriteData(0x00);
	LCD_WriteData(0x01);
	LCD_WriteData(0x3F);
	LCD_WriteCommand(LCD_INTERFACE);
	LCD_WriteData(0x01);
	LCD_WriteData(0x00);
	LCD_WriteData(0x06);

	LCD_WriteCommand(LCD_GRAM);
	delayMs(200);

	LCD_WriteCommand(LCD_GAMMA);
	LCD_WriteData(0x01);

	LCD_WriteCommand(LCD_PGAMMA);
	LCD_WriteData(0x0F);
	LCD_WriteData(0x29);
	LCD_WriteData(0x24);
	LCD_WriteData(0x0C);
	LCD_WriteData(0x0E);
	LCD_WriteData(0x09);
	LCD_WriteData(0x4E);
	LCD_WriteData(0x78);
	LCD_WriteData(0x3C);
	LCD_WriteData(0x09);
	LCD_WriteData(0x13);
	LCD_WriteData(0x05);
	LCD_WriteData(0x17);
	LCD_WriteData(0x11);
	LCD_WriteData(0x00);
	LCD_WriteCommand(LCD_NGAMMA);
	LCD_WriteData(0x00);
	LCD_WriteData(0x16);
	LCD_WriteData(0x1B);
	LCD_WriteData(0x04);
	LCD_WriteData(0x11);
	LCD_WriteData(0x07);
	LCD_WriteData(0x31);
	LCD_WriteData(0x33);
	LCD_WriteData(0x42);
	LCD_WriteData(0x05);
	LCD_WriteData(0x0C);
	LCD_WriteData(0x0A);
	LCD_WriteData(0x28);
	LCD_WriteData(0x2F);
	LCD_WriteData(0x0F);

	LCD_WriteCommand(LCD_SLEEP_OUT);
	delayMs(200);
	LCD_WriteCommand(LCD_DISPLAY_ON);
	/* GRAM start writing */
	LCD_WriteCommand(LCD_GRAM);
}

/**
  * @brief  Enables the Display.
  * @param  None
  * @retval None
  */
void LCD_DisplayOn(void)
{
	LCD_WriteCommand(LCD_DISPLAY_ON);
}

/**
  * @brief  Disables the Display.
  * @param  None
  * @retval None
  */
void LCD_DisplayOff(void)
{
	/* Display Off */
	LCD_WriteCommand(LCD_DISPLAY_OFF);
}

/**
  * @brief  Configures LCD control lines in Output Push-Pull mode.
  * @note   The LCD_NCS line can be configured in Open Drain mode
  *         when VDDIO is lower than required LCD supply.
  * @param  None
  * @retval None
  */
void LCD_CtrlLinesConfig(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/* Enable GPIOs clock*/
	RCC_AHB1PeriphClockCmd(LCD_NCS_GPIO_CLK | LCD_WRX_GPIO_CLK, ENABLE);

	/* Configure NCS in Output Push-Pull mode */
	GPIO_InitStructure.GPIO_Pin = LCD_NCS_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(LCD_NCS_GPIO_PORT, &GPIO_InitStructure);

	/* Configure WRX in Output Push-Pull mode */
	GPIO_InitStructure.GPIO_Pin = LCD_WRX_PIN;
	GPIO_Init(LCD_WRX_GPIO_PORT, &GPIO_InitStructure);

	/* Set chip select pin high */
	LCD_CtrlLinesWrite(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, Bit_SET);
}

/**
  * @brief  Sets or reset LCD control lines.
  * @param  GPIOx: where x can be B or D to select the GPIO peripheral.
  * @param  CtrlPins: the Control line.
  *   This parameter can be:
  *     @arg LCD_NCS_PIN: Chip Select pin
  *     @arg LCD_NWR_PIN: Read/Write Selection pin
  *     @arg LCD_RS_PIN: Register/RAM Selection pin
  * @param  BitVal: specifies the value to be written to the selected bit.
  *   This parameter can be:
  *     @arg Bit_RESET: to clear the port pin
  *     @arg Bit_SET: to set the port pin
  * @retval None
  */
void LCD_CtrlLinesWrite(GPIO_TypeDef* GPIOx, uint16_t CtrlPins, BitAction BitVal)
{
	/* Set or Reset the control line */
	GPIO_WriteBit(GPIOx, (uint16_t)CtrlPins, (BitAction)BitVal);
}

/**
  * @brief  Configures the LCD_SPI interface.
  * @param  None
  * @retval None
  */
void LCD_SPIConfig(void)
{
	SPI_InitTypeDef    SPI_InitStructure;
	GPIO_InitTypeDef   GPIO_InitStructure;

	/* Enable LCD_SPI_SCK_GPIO_CLK, LCD_SPI_MISO_GPIO_CLK and LCD_SPI_MOSI_GPIO_CLK clock */
	RCC_AHB1PeriphClockCmd(LCD_SPI_SCK_GPIO_CLK | LCD_SPI_MISO_GPIO_CLK | LCD_SPI_MOSI_GPIO_CLK, ENABLE);

	/* Enable LCD_SPI and SYSCFG clock  */
	RCC_APB2PeriphClockCmd(LCD_SPI_CLK, ENABLE);

	/* Configure LCD_SPI SCK pin */
	GPIO_InitStructure.GPIO_Pin = LCD_SPI_SCK_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
	GPIO_Init(LCD_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);

	/* Configure LCD_SPI MISO pin */
	GPIO_InitStructure.GPIO_Pin = LCD_SPI_MISO_PIN;
	GPIO_Init(LCD_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);

	/* Configure LCD_SPI MOSI pin */
	GPIO_InitStructure.GPIO_Pin = LCD_SPI_MOSI_PIN;
	GPIO_Init(LCD_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);

	/* Connect SPI SCK */
	GPIO_PinAFConfig(LCD_SPI_SCK_GPIO_PORT, LCD_SPI_SCK_SOURCE, LCD_SPI_SCK_AF);

	/* Connect SPI MISO */
	GPIO_PinAFConfig(LCD_SPI_MISO_GPIO_PORT, LCD_SPI_MISO_SOURCE, LCD_SPI_MISO_AF);

	/* Connect SPI MOSI */
	GPIO_PinAFConfig(LCD_SPI_MOSI_GPIO_PORT, LCD_SPI_MOSI_SOURCE, LCD_SPI_MOSI_AF);

	SPI_I2S_DeInit(LCD_SPI);

	/* SPI configuration -------------------------------------------------------*/
	/* If the SPI peripheral is already enabled, don't reconfigure it */
	if ((LCD_SPI->CR1 & SPI_CR1_SPE) == 0)
	{
		SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
		SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
		SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
		SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
		SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
		SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
		/* SPI baudrate is set to 5.6 MHz (PCLK2/SPI_BaudRatePrescaler = 90/16 = 5.625 MHz)
		   to verify these constraints:
		   - ILI9341 LCD SPI interface max baudrate is 10MHz for write and 6.66MHz for read
		   - l3gd20 SPI interface max baudrate is 10MHz for write/read
		   - PCLK2 frequency is set to 90 MHz
		   */
		SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
		SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
		SPI_InitStructure.SPI_CRCPolynomial = 7;
		SPI_Init(LCD_SPI, &SPI_InitStructure);

		/* Enable L3GD20_SPI  */
		SPI_Cmd(LCD_SPI, ENABLE);
	}
}

/**
  * @brief  GPIO config for LTDC.
  * @param  None
  * @retval None
  */
void LCD_AF_GPIOConfig(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;

	/* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOF, GPIOG AHB Clocks */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | \
		RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | \
		RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG, ENABLE);

	/* GPIOs Configuration */
	/*
	 +------------------------+-----------------------+----------------------------+
	 +                       LCD pins assignment                                   +
	 +------------------------+-----------------------+----------------------------+
	 |  LCD_TFT R2 <-> PC.10  |  LCD_TFT G2 <-> PA.06 |  LCD_TFT B2 <-> PD.06      |
	 |  LCD_TFT R3 <-> PB.00  |  LCD_TFT G3 <-> PG.10 |  LCD_TFT B3 <-> PG.11      |
	 |  LCD_TFT R4 <-> PA.11  |  LCD_TFT G4 <-> PB.10 |  LCD_TFT B4 <-> PG.12      |
	 |  LCD_TFT R5 <-> PA.12  |  LCD_TFT G5 <-> PB.11 |  LCD_TFT B5 <-> PA.03      |
	 |  LCD_TFT R6 <-> PB.01  |  LCD_TFT G6 <-> PC.07 |  LCD_TFT B6 <-> PB.08      |
	 |  LCD_TFT R7 <-> PG.06  |  LCD_TFT G7 <-> PD.03 |  LCD_TFT B7 <-> PB.09      |
	 -------------------------------------------------------------------------------
	 |  LCD_TFT HSYNC <-> PC.06  | LCDTFT VSYNC <->  PA.04 |
	 |  LCD_TFT CLK   <-> PG.07  | LCD_TFT DE   <->  PF.10 |
	 -----------------------------------------------------

	 */

	/* GPIOA configuration */
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_LTDC);

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_6 | \
		GPIO_Pin_11 | GPIO_Pin_12;

	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA, &GPIO_InitStruct);

	/* GPIOB configuration */
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, 0x09);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource1, 0x09);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_LTDC);

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | \
		GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;

	GPIO_Init(GPIOB, &GPIO_InitStruct);

	/* GPIOC configuration */
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_LTDC);

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_10;

	GPIO_Init(GPIOC, &GPIO_InitStruct);

	/* GPIOD configuration */
	GPIO_PinAFConfig(GPIOD, GPIO_PinSource3, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_LTDC);

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6;

	GPIO_Init(GPIOD, &GPIO_InitStruct);

	/* GPIOF configuration */
	GPIO_PinAFConfig(GPIOF, GPIO_PinSource10, GPIO_AF_LTDC);

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;

	GPIO_Init(GPIOF, &GPIO_InitStruct);

	/* GPIOG configuration */
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource6, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource7, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource10, 0x09);
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource11, GPIO_AF_LTDC);
	GPIO_PinAFConfig(GPIOG, GPIO_PinSource12, 0x09);

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_10 | \
		GPIO_Pin_11 | GPIO_Pin_12;

	GPIO_Init(GPIOG, &GPIO_InitStruct);

}

/**
  * @brief  Displays a pixel.
  * @param  x: pixel x.
  * @param  y: pixel y.
  * @retval None
  */
void PutPixel(int16_t x, int16_t y)
{
	if (x < 0 || x > 239 || y < 0 || y > 319)
		return;
	LCD_DrawLine(x, y, 1, LCD_DIR_HORIZONTAL);
}
